gusucode.com > VC++ 车牌识别源代码-源码程序 > VC++ 车牌识别源代码-源码程序/code/Plate/PlateLocateMethod.cpp

    //Download by http://www.NewXing.com
/**************************************************************************
*  文件名:PlateLocateMethod.cpp
*
*  车牌定位函数库:
*  
*  ConvertToGrayScale();   - 24位真彩色图转换成灰度图
*************************************************************************/

#include "stdafx.h"
#include "PlateLocateMethod.h"
#include "math.h"

/*************************************************************************
*
* 函数名称:
*   ConvertToGrayScale()
*
* 参数:
*   LPSTR lpDIB			- 指向源DIB图像指针
*   
* 返回值:
*   BOOL					- 成功返回TRUE,否则返回FALSE。
*
* 说明:
*   该函数将24位真彩色图转换成256级灰度图
*
************************************************************************/
BOOL WINAPI ConvertToGrayScale(LPSTR lpDIB)   
{
	
	LPSTR lpDIBBits;                //指向DIB的象素的指针
	LPSTR lpNewDIBBits;             //指向DIB灰度图图像(新图像)开始处象素的指针
    LONG lLineBytes;
	unsigned char * lpSrc;          //指向原图像象素点的指针
	unsigned char * lpdest;         //指向目标图像象素点的指针
	
    unsigned  char *ired,*igreen,*iblue;
	
    long lWidth;                    //图像宽度和高度
	long lHeight;
	
	long i,j;           //循环变量
	
	lWidth = ::DIBWidth(lpDIB);   //DIB 宽度
	lHeight = ::DIBHeight(lpDIB); //DIB 高度
	RGBQUAD  *lpRGBquad;
	lpRGBquad = (RGBQUAD *)&lpDIB[sizeof(BITMAPINFOHEADER)]; //INFOHEADER后为调色板		
    if(::DIBNumColors(lpDIB) == 256)  //256色位图不作任何处理
	{
		return TRUE;
    }
	
	if(::DIBNumColors(lpDIB) != 256)  //非256色位图将它灰度化
	{
		lLineBytes = WIDTHBYTES(lWidth*8*3);//真彩色一个象素为3个字节
		lpdest=  new  BYTE[lHeight*lWidth];
		lpDIBBits = (LPSTR)lpDIB + sizeof(BITMAPINFOHEADER);//指向DIB象素
		for(i = 0;i < lHeight; i++)
			for(j = 0;j < lWidth*3; j+=3)//每个象素3个字节
			{
				ired   =  (unsigned  char*)lpDIBBits + lLineBytes * i + j + 2;
				igreen =  (unsigned  char*)lpDIBBits + lLineBytes * i + j + 1;
				iblue  =  (unsigned  char*)lpDIBBits + lLineBytes * i +	j ;
				lpdest[i*lWidth + j/3]  = (unsigned  char)((*ired)*0.299 + (*igreen)*0.588 + (*iblue)*0.114);
			}
			
			//需要做三件事情:1、修改INFOHEADER 2、增加调色板 3、修改原图像灰度值
			LPBITMAPINFOHEADER  lpBI;
			lpBI  =  (LPBITMAPINFOHEADER)lpDIB;
			lpBI->biBitCount = 8;
			
			//设置灰度调色板
			for(i = 0;i < 256;i++)
			{
				lpRGBquad[i].rgbRed   = (unsigned char)i;
				lpRGBquad[i].rgbGreen = (unsigned char)i;
				lpRGBquad[i].rgbBlue  = (unsigned char)i;
				lpRGBquad[i].rgbReserved = 0;
			}
			
			lpNewDIBBits= ::FindDIBBits(lpDIB);  //找到DIB图像象素起始位置
			lLineBytes=WIDTHBYTES(lWidth  *  8);
			//修改灰度值
			for(i = 0;i < lHeight; i++)
				for(j = 0;j < lWidth; j++)
				{
					lpSrc = (unsigned  char*)lpNewDIBBits + lLineBytes * i+ j ;
					*lpSrc=lpdest[i*lWidth+j];
				}
				delete  lpdest;
	}	
	return true;
}
/*************************************************************************
 *
 * 函数名称:
 *   InteEqualize()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数)
 *   LONG  lHeight      - 源图像高度(象素数)
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 *   该函数用来对图像进行直方图均衡。
 *
 ************************************************************************/
BOOL WINAPI InteEqualize(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 临时变量
	LONG	lTemp;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 灰度映射表
	BYTE	bMap[256];
	
	// 灰度映射表
	LONG	lCount[256];
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 重置计数为0
	for (i = 0; i < 256; i ++)
	{
		// 清零
		lCount[i] = 0;
	}
	
	// 计算各个灰度值的计数
	for (i = 0; i < lHeight; i ++)
	{
		for (j = 0; j < lWidth; j ++)
		{
			lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
			
			// 计数加1
			lCount[*(lpSrc)]++;
		}
	}
	
	// 计算灰度映射表
	for (i = 0; i < 256; i++)
	{
		// 初始为0
		lTemp = 0;
		
		for (j = 0; j <= i ; j++)
		{
			lTemp += lCount[j];
		}
		
		// 计算对应的新灰度值
		bMap[i] = (BYTE) (lTemp * 255 / (lHeight * lWidth));
	}
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 计算新的灰度值
			*lpSrc = bMap[*lpSrc];
		}
	}
	
	// 返回
	return TRUE;
}
/*************************************************************************
 *
 * 函数名称:
 *   RobertDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用Robert边缘检测算子对图像进行边缘检测运算。
 * 
 * 要求目标图像为灰度图像。
 ************************************************************************/

BOOL WINAPI RobertDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
	
	// 指向源图像的指针
	LPSTR	lpSrc;
	
	// 指向缓存图像的指针
	LPSTR	lpDst;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;

	//循环变量
	long i;
	long j;

	//像素值
	double result;
	unsigned char pixel[4];

	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);

	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);

	// 初始化新分配的内存,设定初始值为255
	lpDst = (char *)lpNewDIBBits;
	memset(lpDst, (BYTE)255, lWidth * lHeight);


	//使用水平方向的结构元素进行腐蚀
	for(j = lHeight-1; j > 0; j--)
	{
		for(i = 0;i <lWidth-1; i++)
		{
			//由于使用2×2的模板,为防止越界,所以不处理最下边和最右边的两列像素

			// 指向源图像第j行,第i个象素的指针			
			lpSrc = (char *)lpDIBBits + lWidth * j + i;

			// 指向目标图像第j行,第i个象素的指针			
			lpDst = (char *)lpNewDIBBits + lWidth * j + i;

			//取得当前指针处2*2区域的像素值,注意要转换为unsigned char型
			pixel[0] = (unsigned char)*lpSrc;
			pixel[1] = (unsigned char)*(lpSrc + 1);
			pixel[2] = (unsigned char)*(lpSrc - lWidth);
			pixel[3] = (unsigned char)*(lpSrc - lWidth + 1);

			//计算目标图像中的当前点
			 result = sqrt(( pixel[0] - pixel[3] )*( pixel[0] - pixel[3] ) + \
				  ( pixel[1] - pixel[2] )*( pixel[1] - pixel[2] ));
			*lpDst = (unsigned char)result;
		
		}
	}

	// 复制腐蚀后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);

	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);

	// 返回
	return TRUE;
}
/*************************************************************************
*
* 函数名称:
*   ThresholdTrans()
*
* 参数:
*   LPSTR lpDIBBits    - 指向源DIB图像指针
*   LONG  lWidth       - 源图像宽度(象素数)
*   LONG  lHeight      - 源图像高度(象素数)
*   BYTE  bThre	    - 阈值
*
* 返回值:
*   BOOL               - 成功返回TRUE,否则返回FALSE。
*
* 说明:
*   该函数用来对图像进行阈值变换。对于灰度值小于阈值的象素直接设置
* 灰度值为0;灰度值大于阈值的象素直接设置为255。
*
************************************************************************/
BOOL WINAPI ThresholdTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bThre)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 每行
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 判断是否小于阈值
			if ((*lpSrc) < bThre)
			{
				// 直接赋值为0
				*lpSrc = 0;
			}
			else
			{
				// 直接赋值为255
				*lpSrc = 255;
			}
		}
	}
	
	// 返回
	return TRUE;
}

/*************************************************************************
*
* 函数名称:
*   myHprojectDIB()
*
* 参数:
*   LPSTR lpDIBBits    - 指向源DIB图像指针
*   LONG  lWidth       - 源图像宽度(象素数)
*   LONG  lHeight      - 源图像高度(象素数)
*   INT*  iTop         - 车牌上边缘
*   INT*  iBottom      - 车牌下边缘
* 返回值:
*   BOOL               - 成功返回TRUE,否则返回FALSE。
*
* 说明:
*   该函数用于对含车牌图像进行水平投影运算,求取车牌子图像的上下边缘位置
*
************************************************************************/
BOOL WINAPI myHprojectDIB(LPSTR lpDIB, LONG lWidth, LONG lHeight, 
						  int* iTop, int* iBottom) 
{
	LPSTR lpDIBBits;                   //指向DIB的象素的指针
	
    LONG lLineBytes;                   // 图像每行的字节数
	unsigned char * lpSrc;             //指向原图像象素点的指针
	
	unsigned char pixel;				//像素值
	
	int i,j;
	
	// 计算结果
	INT* iResult;
	
	INT pzBottom,pzTop;
	
	bool findPZ=false;
	
	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	iResult=new INT[lHeight];
	
	for(i=0;i<lHeight;i++)
		iResult[i]=0;
	
	for(j=lHeight/7;j<lHeight*0.8;j++)
	{
		iResult[j]=0;
		for(i=0;i<lWidth;i++)
		{
			lpSrc=(unsigned char*)lpDIBBits+lLineBytes*j+i;
			pixel=(unsigned char)(*lpSrc);
			if(pixel==255)
			{
				iResult[j]++;
			}
		}
		if((!findPZ)&&iResult[j]>12)
		{
			pzBottom=j;
			findPZ=true;
			continue;
		}
		if(findPZ&&iResult[j]<12)
		{
			pzTop=j;
			break;
		}
		
	}
	if(pzTop - pzBottom < 40)
	{
	pzTop=pzTop+55;
	pzBottom=pzBottom-20;   //微量调整
	}
	*iBottom=lHeight-pzBottom;
	//*iBottom=pzBottom;
	*iTop=lHeight-pzTop;
	//*iTop=pzTop;
	return true;
}

/*************************************************************************
*
* 函数名称:
*   myVprojectDIB()
*
* 参数:
*   LPSTR lpDIBBits    - 指向源DIB图像指针
*   LONG  lWidth       - 源图像宽度(象素数)
*   LONG  lHeight      - 源图像高度(象素数)
*   INT*  iLeft        - 车牌左边缘
*   INT*  iRight       - 车牌右边缘
* 返回值:
*   BOOL               - 成功返回TRUE,否则返回FALSE。
*
* 说明:
*   该函数用于对含车牌图像进行垂直投影运算,求取车牌子图像的左右边缘位置
*
************************************************************************/
BOOL WINAPI myVprojectDIB(LPSTR lpDIB, LONG lWidth, LONG lHeight, 
						  int* iLeft, int* iRight) 
{
	LPSTR lpDIBBits;                   //指向DIB的象素的指针
	
    LONG lLineBytes;                   // 图像每行的字节数
	unsigned char * lpSrc;             //指向原图像象素点的指针
	
	unsigned char pixel;				//像素值
	
	int i,j;
	
	// 计算结果
	INT* iResult;
	
	INT pzLeft,pzRight;
	
	bool findPZ=false;
	
	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	iResult=new INT[lWidth];
	
	for(i=0;i<lWidth;i++)
		iResult[i]=0;
	
	for(i=lWidth/7;i<lWidth*0.8;i++)
	{
		iResult[i]=0;
		for(j=0;j<lHeight;j++)
		{
			lpSrc=(unsigned char*)lpDIBBits+lLineBytes*j+i;
			pixel=(unsigned char)(*lpSrc);
			if(pixel==255)
			{
				iResult[i]++;
			}
		}
		if((!findPZ)&&iResult[i]>12)
		{
			pzLeft=i;
			findPZ=true;
			continue;
		}

		pzRight=pzLeft+150;
	}
	
	*iLeft=pzLeft-10;
	*iRight=pzRight+10;
	return true;
}

/*************************************************************************
*
* 函数名称:
*   Template()
*
* 参数:
*   LPSTR lpDIBBits    - 指向源DIB图像指针
*   LONG  lWidth       - 源图像宽度(象素数)
*   LONG  lHeight      - 源图像高度(象素数)
*   int   iTempH		- 模板的高度
*   int   iTempW		- 模板的宽度
*   int   iTempMX		- 模板的中心元素X坐标 ( < iTempW - 1)
*   int   iTempMY		- 模板的中心元素Y坐标 ( < iTempH - 1)
*	 FLOAT * fpArray	- 指向模板数组的指针
*	 FLOAT fCoef		- 模板系数
*
* 返回值:
*   BOOL               - 成功返回TRUE,否则返回FALSE。
*
* 说明:
*   该函数用指定的模板(任意大小)来对图像进行操作,参数iTempH指定模板
* 的高度,参数iTempW指定模板的宽度,参数iTempMX和iTempMY指定模板的中心
* 元素坐标,参数fpArray指定模板元素,fCoef指定系数。
*
************************************************************************/

BOOL WINAPI myTemplate(LPSTR lpDIB)			
{
	// 指向复制图像的指针
	LPSTR	lpNewDIBBits;
	HLOCAL	hNewDIBBits;
	
	// 指向要复制区域的指针
	unsigned char*	lpDst;
	
	LPSTR lpDIBBits;                   //指向DIB的象素的指针
	
    LONG lLineBytes;                   // 图像每行的字节数
	unsigned char * lpSrc;             //指向原图像象素点的指针
	
    long lWidth;                       //图像宽度和高度
	long lHeight;
	
	// 计算结果
	INT	fResult1;
	INT fResult2;
	INT fResult;
	
	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	lWidth = ::DIBWidth(lpDIB);   //DIB 宽度
	lHeight = ::DIBHeight(lpDIB); //DIB 高度
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);
	
	// 判断是否内存分配失败
	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return false;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
	
	// 初始化图像为原始图像
	memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight);
	
	
	long i,j;           //循环变量
	
	//
	//不对边缘进行处理
	for(i = 0; i < lHeight; i++)
	{
		// 每列
		for(j = 0; j < lWidth; j++)
		{
			// 指向新DIB第i行,第j个象素的指针
			lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			fResult1=abs((*lpSrc)-(*(lpSrc+1)));
			fResult2=abs((*lpSrc)-(*(lpSrc+lWidth)));

			if(fResult1 < fResult2)
				fResult = fResult2;
			else fResult = fResult1;
			
			// 取绝对值
			if(fResult<0) fResult=-fResult;
			
			// 判断是否超过255
			if(fResult > 255)
			{
				// 直接赋值为255
				* lpDst = 255;
			}
			else
			{
				// 赋值
				* lpDst = (unsigned char) (fResult + 0.5);
			}
			
		}
	}
	
	// 复制变换后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight);
	
	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);
	
	// 返回
	return TRUE;
}
/*************************************************************************
*
* 函数名称:
*   myCropDIB()
*
* 参数:
*   HDIB hDIB          - 指向源DIB图像句柄
*   LPRECT lpRect      - 指向要剪裁的矩形区域
*
* 返回值:
*   HDIB               - 返回裁剪后的矩形区域图像句柄。
*
* 说明:
* 该函数用于对指定图像进行指定区域裁剪操作。
* 
* 要求目标图像为255个灰度值的灰度图像。
************************************************************************/

HDIB WINAPI myCropDIB(HDIB hDIB, LPRECT lpRect)
{
	
	LPBITMAPINFO lpbmi = NULL; 
    LPBYTE       lpSourceBits, lpTargetBits, lpResult; 
    HDC			 hDC = NULL, hSourceDC, hTargetDC; 
    HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap; 
    DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize; 
	int			 nWidth, nHeight;
	HDIB		 hNewDIB;
	DWORD		 dwSize;
	
	// Get DIB pointer
	if (! hDIB)
	{
		return NULL;
	}
	LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO)GlobalLock(hDIB);
	if (! lpSrcDIB)
	{
		return NULL;
	}
	
    // Allocate and fill out a BITMAPINFO struct for the new DIB 
    dwTargetHeaderSize = sizeof( BITMAPINFOHEADER ) + PaletteSize((LPSTR)lpSrcDIB); 
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize ); 
	memcpy(lpbmi, lpSrcDIB, dwTargetHeaderSize);
	nWidth = RECTWIDTH(lpRect);
	nHeight = RECTHEIGHT(lpRect);
    lpbmi->bmiHeader.biWidth = nWidth; 
    lpbmi->bmiHeader.biHeight = nHeight; 
	
    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em 
	hDC = ::GetDC( NULL ); 
    hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 ); 
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 ); 
    hSourceDC = CreateCompatibleDC( hDC ); 
    hTargetDC = CreateCompatibleDC( hDC ); 
	
    // Flip the bits on the source DIBSection to match the source DIB 
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader)); 
    dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader)); 
    memcpy( lpSourceBits, FindDIBBits((LPSTR)lpSrcDIB), dwSourceBitsSize ); 
    lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize; 
	
    // Select DIBSections into DCs 
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap ); 
    hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap ); 
	
	// put old bitmap in new bitmap 
    BitBlt(hTargetDC, 0, 0, nWidth, nHeight, hSourceDC, lpRect->left, lpRect->top, SRCCOPY); 
	
    // Clean up and delete the DCs 
    SelectObject( hSourceDC, hOldSourceBitmap ); 
    SelectObject( hTargetDC, hOldTargetBitmap ); 
    DeleteDC( hSourceDC ); 
    DeleteDC( hTargetDC ); 
    ::ReleaseDC( NULL, hDC ); 
	
    // Flush the GDI batch, so we can play with the bits 
    GdiFlush(); 
	
    // Allocate enough memory for the new CF_DIB, and copy bits 
	dwSize = dwTargetHeaderSize + dwTargetBitsSize;
	hNewDIB =(HDIB)GlobalAlloc(GHND, dwSize);
    lpResult = (LPBYTE)GlobalLock(hNewDIB);//malloc( dwTargetHeaderSize + dwTargetBitsSize ); 
    memcpy( lpResult, lpbmi, dwTargetHeaderSize ); 
    memcpy( FindDIBBits( (LPSTR)lpResult ), lpTargetBits, dwTargetBitsSize ); 
	
    // final cleanup 
    DeleteObject( hTargetBitmap ); 
    DeleteObject( hSourceBitmap ); 
    free( lpbmi ); 
	GlobalUnlock(hDIB);
	GlobalUnlock(hNewDIB);
	
    return hNewDIB;
}

/*************************************************************************
*
* 函数名称:
*   MedianFilter()
*
* 参数:
*   LPSTR lpDIBBits		- 指向源DIB图像指针
*   LONG  lWidth			- 源图像宽度(象素数)
*   LONG  lHeight			- 源图像高度(象素数)
*   int   iFilterH			- 滤波器的高度
*   int   iFilterW			- 滤波器的宽度
*   int   iFilterMX		- 滤波器的中心元素X坐标
*   int   iFilterMY		- 滤波器的中心元素Y坐标
*
* 返回值:
*   BOOL					- 成功返回TRUE,否则返回FALSE。
*
* 说明:
*   该函数对DIB图像进行中值滤波。
*
************************************************************************/

BOOL WINAPI myMedianFilter(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, 
						   int iFilterH, int iFilterW, 
						   int iFilterMX, int iFilterMY)
{
	
	// 指向源图像的指针
	unsigned char*	lpSrc;
	
	// 指向要复制区域的指针
	unsigned char*	lpDst;
	
	// 指向复制图像的指针
	LPSTR			lpNewDIBBits;
	HLOCAL			hNewDIBBits;
	
	// 指向滤波器数组的指针
	unsigned char	* aValue;
	HLOCAL			hArray;
	
	// 循环变量
	LONG			i;
	LONG			j;
	LONG			k;
	LONG			l;
	
	// 图像每行的字节数
	LONG			lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);
	
	// 暂时分配内存,以保存新图像
	hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);
	
	// 判断是否内存分配失败
	if (hNewDIBBits == NULL)
	{
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
	
	// 初始化图像为原始图像
	memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight);
	
	// 暂时分配内存,以保存滤波器数组
	hArray = LocalAlloc(LHND, iFilterH * iFilterW);
	
	// 判断是否内存分配失败
	if (hArray == NULL)
	{
		// 释放内存
		LocalUnlock(hNewDIBBits);
		LocalFree(hNewDIBBits);
		
		// 分配内存失败
		return FALSE;
	}
	
	// 锁定内存
	aValue = (unsigned char * )LocalLock(hArray);
	
	// 开始中值滤波
	// 行(除去边缘几行)
	for(i = iFilterMY; i < lHeight - iFilterH + iFilterMY + 1; i++)
	{
		// 列(除去边缘几列)
		for(j = iFilterMX; j < lWidth - iFilterW + iFilterMX + 1; j++)
		{
			// 指向新DIB第i行,第j个象素的指针
			lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 读取滤波器数组
			for (k = 0; k < iFilterH; k++)
			{
				for (l = 0; l < iFilterW; l++)
				{
					// 指向DIB第i - iFilterMY + k行,第j - iFilterMX + l个象素的指针
					lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i + iFilterMY - k) + j - iFilterMX + l;
					
					// 保存象素值
					aValue[k * iFilterW + l] = *lpSrc;
				}
			}
			
			// 获取中值
			* lpDst = myGetMedianNum(aValue, iFilterH * iFilterW);
		}
	}
	
	// 复制变换后的图像
	memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight);
	
	// 释放内存
	LocalUnlock(hNewDIBBits);
	LocalFree(hNewDIBBits);
	LocalUnlock(hArray);
	LocalFree(hArray);
	
	// 返回
	return TRUE;
}

/*************************************************************************
*
* 函数名称:
*   GetMedianNum()
*
* 参数:
*   unsigned char * bpArray	- 指向要获取中值的数组指针
*   int   iFilterLen			- 数组长度
*
* 返回值:
*   unsigned char      - 返回指定数组的中值。
*
* 说明:
*   该函数用冒泡法对一维数组进行排序,并返回数组元素的中值。
*
************************************************************************/

unsigned char WINAPI myGetMedianNum(unsigned char * bArray, int iFilterLen)
{
	// 循环变量
	int		i;
	int		j;
	
	// 中间变量
	unsigned char bTemp;
	
	// 用冒泡法对数组进行排序
	for (j = 0; j < iFilterLen - 1; j ++)
	{
		for (i = 0; i < iFilterLen - j - 1; i ++)
		{
			if (bArray[i] > bArray[i + 1])
			{
				// 互换
				bTemp = bArray[i];
				bArray[i] = bArray[i + 1];
				bArray[i + 1] = bTemp;
			}
		}
	}
	
	// 计算中值
	if ((iFilterLen & 1) > 0)
	{
		// 数组有奇数个元素,返回中间一个元素
		bTemp = bArray[(iFilterLen + 1) / 2];
	}
	else
	{
		// 数组有偶数个元素,返回中间两个元素平均值
		bTemp = (bArray[iFilterLen / 2] + bArray[iFilterLen / 2 + 1]) / 2;
	}
	
	// 返回中值
	return bTemp;
}
/***************************************************************************
***************************************************************************/
BOOL WINAPI myFindRightAngle(CDC* pDC,LPSTR lpDIB,int* iLeft,int* iTop,int* iRight,int* iBottom)
{
	LPSTR lpDIBBits;                   //指向DIB的象素的指针
	
    LONG lLineBytes;                   // 图像每行的字节数
	unsigned char * lpSrc;             //指向原图像象素点的指针
	
	unsigned char pixel = 0;				//像素值
	
	long lWidth;                       //图像宽度和高度
	long lHeight;

	int i = 0,j = 0;
	int lineRequired = 12;//确定一条直线至少要18个象素
	int lineLimited  = 20;//为确定一条直线应该扫描25个象素
	int linePixelCount = 0;//已扫描到的灰度值为255的象素点
	int pixelCount = 0;//扫描象素时的循环变量

	CPen newRedPen(PS_SOLID,2,RGB(255,0,0));
	pDC->SelectObject(newRedPen);
	HGDIOBJ brush=GetStockObject(NULL_BRUSH);
	pDC->SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));

    //INT pzBottom,pzTop,pzLeft,pzRight;
	struct topLeftCorner {
		int pzTop;
		int pzLeft;
	}topLeft[1000];

	struct bottomRightCorner {
		int pzBottom;
		int pzRight;
	}bottomRight[1000];

	int  tlCount = 0;//左上角数组的索引
	int  brCount = 0;//右下角数组的索引
	bool findTL=false;                  //是否找到左上角
	bool findBR=false;                  //是否找到右下角
	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	lWidth = ::DIBWidth(lpDIB);   //DIB 宽度
	lHeight = ::DIBHeight(lpDIB); //DIB 高度
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(lWidth * 8);

	for(i = 0;i < 100;i++)
	{
		topLeft[i].pzTop = 0;
		topLeft[i].pzLeft = 0;
	}

	for(i = 0;i < 100;i++)
	{
		bottomRight[i].pzBottom = 0;
		bottomRight[i].pzRight = 0;
	}

    //计算左上角的位置,可能有多个,保存在topLeft数组中
	for(i = 30;i < lHeight - 30;i++)//考虑到车牌的大小,在边缘一定范围内可以不考虑
	{
		linePixelCount = 0;
		for(j = 30;j < lWidth - 30 ;j++)
		{
			linePixelCount = 0;
			
			for(pixelCount = j;pixelCount < (j + lineLimited);pixelCount++)//计算直线
			{
				lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + pixelCount;
			    pixel=(unsigned char)(*lpSrc);
			    if(pixel == 255)
				{
				    linePixelCount++;
					//pDC->MoveTo(j,i);
				    //pDC->LineTo(j,i);
				}
			}
			/*if(linePixelCount >= lineRequired)
			{
				pDC->MoveTo(j,i);
				pDC->LineTo(j,i);
			}*/
			if(linePixelCount >= lineRequired)
			{
				linePixelCount = 0;
				for(pixelCount = i;pixelCount < (i + lineLimited);pixelCount++)
				{
					lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - pixelCount) + j;
			        pixel=(unsigned char)(*lpSrc);
			        if(pixel == 255)
					{
				        linePixelCount++;
						//pDC->MoveTo(j,i);
				        //pDC->LineTo(j,i);
					}
				}
			}
			if(linePixelCount >= lineRequired)
			{
				findTL = true;
			}
			if(findTL)
			{
				findTL = false;
				linePixelCount = 0;
				topLeft[tlCount].pzTop = i;
				topLeft[tlCount].pzLeft = j;
				pDC->MoveTo(j,i);
				pDC->LineTo(j,i);
				tlCount++;
			}
		}
	}

    CPen newGreenPen(PS_SOLID,2,RGB(0,255,0));
	pDC->SelectObject(newGreenPen);
	//计算右下角的位置,可能有多个,保存在bottomRight数组中
	linePixelCount = 0;//重新初始化计数器
	for(i = 10;i < lHeight - 10;i++)//考虑到车牌的大小,在边缘一定范围内可以不考虑
	{
		linePixelCount = 0;
		for(j = 20;j < lWidth - 20;j++)
		{
			linePixelCount = 0;
			for(pixelCount = j;pixelCount < (j + lineLimited);pixelCount++)//计算直线
			{
				lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + pixelCount;
			    pixel=(unsigned char)(*lpSrc);
			    if(pixel == 255)
				{
				    linePixelCount++;
				}
			}
			if(linePixelCount >= lineRequired)
			{
				linePixelCount = 0;
				for(pixelCount = i;pixelCount > (i - lineLimited);pixelCount--)
				{
					lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - pixelCount) + lineRequired + j;
			        pixel=(unsigned char)(*lpSrc);
			        if(pixel == 255)
					{
				        linePixelCount++;
					}
				}
				if(linePixelCount >= lineRequired)
				{
					findBR = true;
				}
			}
			if(findBR)
			{
				findBR = false;
				linePixelCount = 0;
				bottomRight[brCount].pzBottom = i;
				bottomRight[brCount].pzRight = j + lineRequired;
				pDC->MoveTo(j + lineRequired,i);
				pDC->LineTo(j + lineRequired,i);
				brCount++;
			}
		}
	}
    
    //计算车牌的位置
	int plateUpHeight = 50;
	int plateDownHeight = 30;
	int plateUpWidth = 100;
	int plateDownWidth = 80;
	bool plateFind = false;
	for(i = 0;i < tlCount;i++)
	{
		for(j = brCount - 1 ;j >= 0;j--)
		{
			if((bottomRight[j].pzBottom - topLeft[i].pzTop > plateDownHeight) &&
				(bottomRight[j].pzBottom - topLeft[i].pzTop < plateUpHeight) && 
				(bottomRight[j].pzRight - topLeft[i].pzLeft > plateDownWidth) && 
				(bottomRight[j].pzRight - topLeft[i].pzLeft < plateUpWidth) &&
				(double(bottomRight[j].pzRight - topLeft[i].pzLeft) / (bottomRight[j].pzBottom - topLeft[i].pzTop)) > 2)
			{
				*iTop = topLeft[i].pzTop;
				*iLeft = topLeft[i].pzLeft;
				*iBottom = bottomRight[j].pzBottom + 10;
				*iRight = bottomRight[j].pzRight + 15;
				plateFind = true;
				break;
			}
			else
			{
				//i++;
				//j--;
			}
		}
		if(plateFind) break;
	}

	/**iTop = topLeft[0].pzTop;
	*iLeft = topLeft[0].pzLeft;
	*iBottom = bottomRight[0].pzBottom;
	*iRight = bottomRight[0].pzRight;*/
	return true;
}
/*************************************************************************
*在图像上画一个矩形
*
*
*
*************************************************************************/
BOOL WINAPI DrawRectangle(CDC* pDC,int iLeft,int iTop,int iRight,int iBottom)
{
	CPen newPen(PS_SOLID,2,RGB(255,0,0));
	pDC->SelectObject(newPen);
	HGDIOBJ brush=GetStockObject(NULL_BRUSH);
	pDC->SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));

	pDC->Rectangle(iLeft,iTop,iRight,iBottom);
	return true;
}